package com.yby6.web.controller.face;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollectionUtil;
import com.arcsoft.face.FaceInfo;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.yby6.common.core.AjaxResult;
import com.yby6.common.core.domain.SysUser;
import com.yby6.common.satoken.LoginHelper;
import com.yby6.common.utils.ServletUtils;
import com.yby6.common.utils.file.ImageUtils;
import com.yby6.face.domain.SysUserFaceInfo;
import com.yby6.face.dto.FaceSearchResDto;
import com.yby6.face.dto.FaceUserInfo;
import com.yby6.face.dto.ProcessInfo;
import com.yby6.face.enums.ErrorCodeEnum;
import com.yby6.face.service.FaceEngineService;
import com.yby6.face.service.SysUserFaceInfoService;
import com.yby6.framework.fastdfs.UploadService;
import com.yby6.framework.web.service.SysLoginService;
import com.yby6.system.service.SysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.List;
import java.util.Map;

/**
 * @program: yangbuyi-rbac
 * @ClassName: FaceController
 * @create: 2022-04-24 01:20
 * @author: Yang Shuai
 * @since： JDK1.8
 * @deprecated : $人脸识别操作
 **/


@RestController
@Slf4j
@RequestMapping("face")
@RequiredArgsConstructor
public class FaceController {
    public final static Logger logger = LoggerFactory.getLogger(FaceController.class);

    private final FaceEngineService faceEngineService;

    private final SysUserFaceInfoService userFaceInfoService;

    private final SysUserService sysUserService;

    private final UploadService uploadService;


    private final SysLoginService sysLoginService;


    /**
     * 人脸添加
     *
     * @param map file    人脸附件
     *            groupId 分组id
     *            name    用户登录名称
     */
    @RequestMapping(value = "/faceAdd", method = RequestMethod.POST)
    public AjaxResult faceAdd(@RequestBody Map<String, Object> map) {
        // 1.判断是否进行了绑定
        final Long id = LoginHelper.getUserId();
        SysUserFaceInfo one = this.userFaceInfoService.lambdaQuery().eq(SysUserFaceInfo::getFaceId, id).one();
        String file = String.valueOf(map.get("file"));
        String groupId = String.valueOf(map.get("groupId"));
        String name = String.valueOf(map.get("name"));
        try {
            if (file == null) {
                return AjaxResult.error("file is null");
            }
            if (groupId == null) {
                return AjaxResult.error("file is null");
            }
            if (name == null) {
                return AjaxResult.error("file is null");
            }
            // 转换实体
            byte[] decode = Base64.decode(base64Process(file));
            ImageInfo imageInfo = ImageFactory.getRGBData(decode);

            //人脸特征获取
            byte[] bytes = faceEngineService.extractFaceFeature(imageInfo);
            if (bytes == null) {
                return AjaxResult.error(ErrorCodeEnum.NO_FACE_DETECTED.getDescription());
            }
            List<ProcessInfo> processInfoList = faceEngineService.process(imageInfo);
            // 开始将人脸识别Base64转换文件流
            final MultipartFile multipartFile = ImageUtils.base64ToMultipartFile(file);
            // 上传七牛云
            final String path = uploadService.qiniuOssUploadFile(multipartFile);
            synchronized (id.toString().intern()) {
                // 如果存在则更新人脸和特征
                if (null != one) {
                    this.userFaceInfoService.lambdaUpdate().set(SysUserFaceInfo::getFaceFeature, bytes).set(SysUserFaceInfo::getFpath, path).eq(SysUserFaceInfo::getFaceId, String.valueOf(id)).update();
                } else {
                    // 组装人脸实体
                    SysUserFaceInfo userFaceInfo = new SysUserFaceInfo();
                    userFaceInfo.setName(name);
                    userFaceInfo.setAge(processInfoList.get(0).getAge());
                    userFaceInfo.setGender(processInfoList.get(0).getGender().shortValue());
                    userFaceInfo.setGroupId(Integer.valueOf(groupId));
                    userFaceInfo.setFaceFeature(bytes);
                    userFaceInfo.setFpath(path);
                    userFaceInfo.setFaceId(String.valueOf(id));
                    //人脸特征插入到数据库
                    userFaceInfoService.insertSysUserFaceInfo(userFaceInfo);
                }
            }
            logger.info("faceAdd:" + name);
            return AjaxResult.success("人脸绑定成功!");
        } catch (Exception e) {
            logger.error("", e);
        }
        return AjaxResult.error(ErrorCodeEnum.UNKNOWN.getDescription());
    }

    /**
     * 人脸识别
     *
     * @param map file    人脸附件
     *            groupId 分组ID 方便快速识别
     */
    @RequestMapping(value = "/faceSearch", method = RequestMethod.POST)
    public AjaxResult faceSearch(@RequestBody Map<String, Object> map) throws Exception {
        String file = String.valueOf(map.get("file"));
        String groupId = String.valueOf(map.get("groupId"));

        if (groupId == null) {
            return AjaxResult.error("groupId is null");
        }
        byte[] decode = Base64.decode(base64Process(file));
        BufferedImage bufImage = ImageIO.read(new ByteArrayInputStream(decode));
        ImageInfo imageInfo = ImageFactory.bufferedImage2ImageInfo(bufImage);


        //人脸特征获取
        byte[] bytes = faceEngineService.extractFaceFeature(imageInfo);
        // 校验是否显示出人脸
        if (bytes == null) {
            return AjaxResult.error(ErrorCodeEnum.NO_FACE_DETECTED.getDescription());
        }

        //人脸比对，获取比对结果
        List<FaceUserInfo> userFaceInfoList = faceEngineService.compareFaceFeature(bytes, Integer.valueOf(groupId));

        if (CollectionUtil.isNotEmpty(userFaceInfoList)) {
            FaceUserInfo faceUserInfo = userFaceInfoList.get(0);
            FaceSearchResDto faceSearchResDto = new FaceSearchResDto();
            BeanUtil.copyProperties(faceUserInfo, faceSearchResDto);
            List<ProcessInfo> processInfoList = faceEngineService.process(imageInfo);
            if (CollectionUtil.isNotEmpty(processInfoList)) {
                //人脸检测
                List<FaceInfo> faceInfoList = faceEngineService.detectFaces(imageInfo);
                int left = faceInfoList.get(0).getRect().getLeft();
                int top = faceInfoList.get(0).getRect().getTop();
                int width = faceInfoList.get(0).getRect().getRight() - left;
                int height = faceInfoList.get(0).getRect().getBottom() - top;

                Graphics2D graphics2D = bufImage.createGraphics();
                // 红色
                graphics2D.setColor(Color.RED);
                BasicStroke stroke = new BasicStroke(5f);
                graphics2D.setStroke(stroke);
                graphics2D.drawRect(left, top, width, height);


                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                ImageIO.write(bufImage, "png", outputStream);
                byte[] bytes1 = outputStream.toByteArray();
                faceSearchResDto.setImage("data:image/jpeg;base64," + Base64Utils.encodeToString(bytes1));
                faceSearchResDto.setAge(processInfoList.get(0).getAge());
                faceSearchResDto.setGender(processInfoList.get(0).getGender().equals(1) ? "女" : "男");
            }
            // 查询用户信息进行授权登录
            final String faceId = faceSearchResDto.getFaceId();
            final SysUser sysUser = sysUserService.getUserInfoByFaceId(faceId);

            // 高强度判断根据用户输入的手机号码后几位or任何唯一身份信息表示通过登录
            // 场景： 可能两个人长得很像识别程度高达九十五以上绕过了人脸识别.
            // 待加入校验


            Serializable login = sysLoginService.login(sysUser, ServletUtils.getRequest());
            log.info("人脸识别登录信息：{}", faceSearchResDto);
            return AjaxResult.success().addParam("token", login);
        }
        return AjaxResult.error(ErrorCodeEnum.FACE_DOES_NOT_MATCH.getDescription());
    }

    /**
     * 检测人脸
     *
     * @param image 人脸图片
     */
    @RequestMapping(value = "/detectFaces", method = RequestMethod.POST)
    public List<FaceInfo> detectFaces(String image) throws IOException {
        byte[] decode = Base64.decode(image);
        InputStream inputStream = new ByteArrayInputStream(decode);
        ImageInfo imageInfo = ImageFactory.getRGBData(inputStream);
        inputStream.close();
        return faceEngineService.detectFaces(imageInfo);
    }


    private String base64Process(String base64Str) {
        if (!StringUtils.isEmpty(base64Str)) {
            String photoBase64 = base64Str.substring(0, 30).toLowerCase();
            int indexOf = photoBase64.indexOf("base64,");
            if (indexOf > 0) {
                base64Str = base64Str.substring(indexOf + 7);
            }

            return base64Str;
        } else {
            return "";
        }
    }

}
